package Algoritmo;

import Grafica.Vertice;
import InterfazPantera.PanteraView;

/**
 *
 * @author robertoanzaldua
 */
public class DFS extends Algoritmo{

    boolean[]visitados;
    Vertice x;
    Vertice v;
    StringBuilder P = new StringBuilder("P = { ");
    Vertice[]p;
    int[]d;
    private static final String c = "0 1 .8";
    static int numM = 0;
    private static String cA = ".3 .8 .6";;

    public DFS(PanteraView interfaz){
        super(interfaz,"DFS");
        p = new Vertice[G.numV];
        d = new int[G.numV];
    }


    private String[] p(){
        String[]pS = new String[G.numV];
        for(int i=0;i<G.numV;i++)
            pS[i] = p[i]!=null ? p[i].ID() : "N";
        return pS;
    }

    private void marca(int v){
        agregaADesarrollo(G.getV(v).ID()+".visitado ← ya\n");
        d[v] = numM++;
        visitados[v] = true;
        marcaVertice(v, c);
        dibuja(d,p());
    }

    /**Nos indica si existe un vértice sin visitar para v.
     * @return  Vertice Un vértice adyacente y sin visitar.
     * @param i El número correspondiente al vértice del
     * que se quiere saber si tiene disponibles
     */
    private Vertice sinVisitar(int i){
        for(Vertice v : G.getV(i).ady())
            if(!visitados[v.nV()])
                return v;
        return null;
    }

    private void inicializa0(){
        agregaADesarrollo("---------------Inicialización-----------------\n");
        visitados = new boolean[G.numV];
        for(int i=0;i<G.numV;i++){
            d[i] = Integer.MAX_VALUE;
            agregaADesarrollo(G.getV(i).ID()+".visitado ← no\n");
        }
    }

    private void inicializa1(){
        cambiaPaso(0,1);
        agregaADesarrollo("\n"+G.aristas(".usada ← no\n")+"\n");
    }

    private void inicializa2(){
        cambiaPaso(1,2);
        x = G.getV(numA(G.numV));
        G.marcaVerticePerm(x.nV(), "#04B404, style=filled");
        agregaADesarrollo("x = "+x.ID()+"\n");
    }

    private void inicializa3(){
        cambiaPaso(2,3);
        agregaADesarrollo(x.ID()+".etiq ← 1\n");
        marcaVertice(x.nV(), c);
        dibuja(d,p());
    }

    private void inicializa4(){
        cambiaPaso(3,4);
        agregaADesarrollo("k ← 2\n");
    }

    private void inicializa5(){
        cambiaPaso(4,5);
        marca(x.nV());
    }

    private void inicializa6(){
        cambiaPaso(5,6);
        P.append(" "+x.ID()+" ");
        agregaADesarrollo("P = <"+x.ID()+">\n");
    }

    private void inicializa7(){
        cambiaPaso(6,7);
        agregaADesarrollo("Este es un proceso para todos los vértices :\n");
        for(int i = 0;i<G.numV;i++){
            agregaADesarrollo("-"+G.getV(i).ID()+"\n");
        }
        agregaADesarrollo("---------------Fin de inicialización-------------\n");
    }

    private void ciclo0(){
        Vertice tmp = sinVisitar(x.nV());
        if(tmp != null){
            cambiaPaso(nulo(7) ? nulo(13) ? 15 : 13 : 7,8);
            agregaADesarrollo(x.disp().ID()+" es adyacente a "+x.ID()+" y aún no se ha visitado\n");
            v = tmp;
        }else{
            cambiaPaso(nulo(13) ? nulo(15) ? 7 : 15 : 13,14);
            agregaADesarrollo("Ya no hay vértices sin visitar que sean vecinos de "+x.ID()+"\n");
            clics0--;
            clics = 9;
        }
    }

    private void ciclo1(){
            cambiaPaso(nulo(8) ? 15 : 8,9);
            marca(v.nV());
    }

    private void ciclo2(){
        cambiaPaso(9,10);
        P.append(v.ID()+" ");
        if(x.disp() != null)
            agregaADesarrollo(P.toString()+"}\n");
    }

    private void ciclo3(){
        cambiaPaso(10,11);
        agregaADesarrollo("e = "+x.ID()+v.ID()+".usada ← ya\n\n");
        G.eliminaArista(x.nV(), v.nV());
        this.marcaArista(x.nV(), v.nV(),"\"" + cA + "\"", true);
        dibuja(d,p());
    }

    private void ciclo4(){
        cambiaPaso(11,12);
        p[v.nV()] = x;
        dibuja(d,p());
        agregaADesarrollo("El predecesor de "+v.ID()+" es: "+x.ID()+"\n");
    }

    private void ciclo5(){
        cambiaPaso(12,13);
        x = v;
        agregaADesarrollo("x ahora es: "+v.ID()+"\n");
    }

    private void cicloF(){
        cambiaPaso(nulo(14) ? 15 : 14 , 15);
        if(p[x.nV()]!=null){            
            agregaADesarrollo(x.ID()+" ← "+x.ID()+".π\n");
            x = p[x.nV()];
            clics = 8;
        }else{
            agregaADesarrollo("x es nulo, el algoritmo ha terminado.");
            clics = 10;
        }
    }


    @Override
    public void ejecutaPaso() {
        switch(clics){
            case 0:
                inicializa0();
                break;
            case 1:
                inicializa1();
                break;
            case 2:
                inicializa2();
                break;
            case 3:
                inicializa3();
                break;
            case 4:
                inicializa4();
                break;
            case 5:
                inicializa5();
                break;
            case 6:
                inicializa6();
                break;
            case 7:
                inicializa7();
                break;
            case 8:
                switch(clics0%6){
                    case 0:
                        ciclo0();
                        break;
                    case 1:
                        ciclo1();
                        break;
                    case 2:
                        ciclo2();
                        break;
                    case 3:
                        ciclo3();
                        break;
                    case 4:
                        ciclo4();
                        break;
                    case 5:
                        ciclo5();
                        break;
                }
                clics0++;
                return;
            case 9:
                cicloF();
                return;
        }
        clics++;
    }
}
